package com.tianquan.DistributedLock.listener;/**
 * @author starsea
 * @date 2024-09-26 下午3:02
 */


import com.tianquan.DistributedLock.entiy.Lock;
import com.tianquan.DistributedLock.entiy.LockEvent;
import com.tianquan.mapper.LockMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.tianquan.DistributedLock.DataBaseLock.get30SecondsTimestamp;
import static com.tianquan.DistributedLock.DataBaseLock.getTimestampOfDateTime;

/**
 * @BelongsProject: uploaddemo
 * @BelongsPackage: com.tianquan.DistributedLock
 * @Author: tianquan
 * @CreateTime: 2024-09-26  15:02
 * @Description: 锁续期监听器
 * @Version: 1.0
 */
@Component
@RequiredArgsConstructor
public class LockRenewalListener implements ApplicationListener<LockEvent> {

    static final Map<Long, Thread> TIME_TASK = new ConcurrentHashMap<>(64);

    private final LockMapper lockMapper;

    public static void deleteRenewalTask(Long threadId) {
        Thread thread = TIME_TASK.get(threadId);
        thread.interrupt();
        TIME_TASK.remove(threadId);
    }

    @Override
    public void onApplicationEvent(LockEvent event) {
        // 给当前线程设置一个守护线程去执行锁续期的任务
        Thread thread = new Thread(new LockRenewalTask(event.getLock(), lockMapper));
        thread.setDaemon(true);
        long id = Thread.currentThread().getId();
        TIME_TASK.put(id, thread);
        thread.start();
    }

    /**
         * @description: 锁续期任务
         * @author: tianquan
         **/
        private record LockRenewalTask(Lock lock, LockMapper lockMapper) implements Runnable {

        @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        Thread.sleep(5000);
                        Long expirationTime = lock.getExpirationTime();
                        // 当前时间戳
                        Long timestampOfDateTime = getTimestampOfDateTime(LocalDateTime.now());
                        // 判断是否需要续期，有效时间不足或等于20秒就需要续期
                        long time = expirationTime - timestampOfDateTime;
                        if (time <= 20000) {
                            // 续期
                            lock.setExpirationTime(get30SecondsTimestamp());
                            lockMapper.renewal(lock);
                            System.out.println("续期成功");
                        }
                    } catch (InterruptedException e) {
                        System.out.println("续期任务结束");
                        return;
                    }
                }
            }
        }
}
